"""
CMDB Views
"""
from rest_framework import viewsets, filters, status
from rest_framework.decorators import api_view, action, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate
from django.contrib.auth.models import User, Group
from django.utils import timezone
from .models import Host, HostGroup, Project, Environment, UserProfile, EmailConfig, AuditLog, InspectionHistory, Role
from .serializers import (
    HostSerializer, HostGroupSerializer, ProjectSerializer,
    EnvironmentSerializer, UserSerializer, UserDetailSerializer,
    GroupSerializer, RegisterSerializer, LoginSerializer, EmailConfigSerializer,
    AuditLogSerializer, InspectionHistorySerializer, RoleSerializer
)
from .permissions import HasPermission, RolePermissionService
import psutil
import platform


class ProjectViewSet(viewsets.ModelViewSet):
    """项目管理视图集"""
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'created_at']


class EnvironmentViewSet(viewsets.ModelViewSet):
    """环境管理视图集"""
    queryset = Environment.objects.all()
    serializer_class = EnvironmentSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'env_type', 'description']
    ordering_fields = ['name', 'env_type', 'created_at']


class HostGroupViewSet(viewsets.ModelViewSet):
    """主机组管理视图集"""
    queryset = HostGroup.objects.all()
    serializer_class = HostGroupSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'created_at']


class HostViewSet(viewsets.ModelViewSet):
    """主机管理视图集"""
    queryset = Host.objects.all()
    serializer_class = HostSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'ip', 'description']
    ordering_fields = ['name', 'ip', 'created_at', 'status']
    permission_classes = [IsAuthenticated]  # 使用自定义权限检查
    
    def check_permission(self, permission_code):
        """检查当前用户是否有指定权限"""
        if self.request.user.is_superuser:
            return True
        return RolePermissionService.has_permission(self.request.user, permission_code)
    
    def list(self, request, *args, **kwargs):
        """查看主机列表"""
        if not self.check_permission('host.view'):
            return Response({'error': '您没有查看主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().list(request, *args, **kwargs)
    
    def retrieve(self, request, *args, **kwargs):
        """查看单个主机"""
        if not self.check_permission('host.view'):
            return Response({'error': '您没有查看主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().retrieve(request, *args, **kwargs)
    
    def create(self, request, *args, **kwargs):
        """创建主机"""
        if not self.check_permission('host.add'):
            return Response({'error': '您没有添加主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().create(request, *args, **kwargs)
    
    def update(self, request, *args, **kwargs):
        """更新主机"""
        if not self.check_permission('host.edit'):
            return Response({'error': '您没有编辑主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().update(request, *args, **kwargs)
    
    def partial_update(self, request, *args, **kwargs):
        """部分更新主机"""
        if not self.check_permission('host.edit'):
            return Response({'error': '您没有编辑主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().partial_update(request, *args, **kwargs)
    
    def destroy(self, request, *args, **kwargs):
        """删除主机"""
        if not self.check_permission('host.delete'):
            return Response({'error': '您没有删除主机的权限'}, status=status.HTTP_403_FORBIDDEN)
        return super().destroy(request, *args, **kwargs)
    
    def get_queryset(self):
        queryset = super().get_queryset()
        project_id = self.request.query_params.get('project')
        environment_id = self.request.query_params.get('environment')
        host_group_id = self.request.query_params.get('host_group')
        status = self.request.query_params.get('status')
        
        if project_id:
            queryset = queryset.filter(project_id=project_id)
        if environment_id:
            queryset = queryset.filter(environment_id=environment_id)
        if host_group_id:
            queryset = queryset.filter(host_group_id=host_group_id)
        if status:
            queryset = queryset.filter(status=status)
        
        return queryset
    
    @action(detail=False, methods=['post'])
    def get_mac_address(self, request):
        """通过SSH获取主机MAC地址"""
        import paramiko
        import re
        
        ip = request.data.get('ip')
        port = request.data.get('port', 22)
        username = request.data.get('username')
        auth_type = request.data.get('auth_type', 'password')
        password = request.data.get('password')
        ssh_key = request.data.get('ssh_key')
        
        if not all([ip, username]):
            return Response(
                {'error': '缺少必要参数：ip和username'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接SSH
            if auth_type == 'password':
                if not password:
                    return Response(
                        {'error': '密码认证需要提供密码'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                ssh.connect(ip, port=port, username=username, password=password, timeout=10)
            else:  # key
                if not ssh_key:
                    return Response(
                        {'error': '密钥认证需要提供SSH密钥'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                from io import StringIO
                key_file = StringIO(ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(ip, port=port, username=username, pkey=pkey, timeout=10)
            
            # 获取MAC地址
            # 尝试多个命令，适配不同系统
            commands = [
                "ip link show | grep 'link/ether' | head -1 | awk '{print $2}'",  # Linux
                "ifconfig | grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' | head -1",  # macOS/BSD
                "cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address"  # Linux alternative
            ]
            
            mac_address = None
            for cmd in commands:
                stdin, stdout, stderr = ssh.exec_command(cmd)
                output = stdout.read().decode('utf-8').strip()
                
                # 验证MAC地址格式
                if output and re.match(r'^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$', output):
                    mac_address = output
                    break
            
            ssh.close()
            
            if mac_address:
                return Response({'mac_address': mac_address})
            else:
                return Response(
                    {'error': '无法获取MAC地址，请手动输入'},
                    status=status.HTTP_404_NOT_FOUND
                )
                
        except paramiko.AuthenticationException:
            return Response(
                {'error': 'SSH认证失败，请检查用户名和密码/密钥'},
                status=status.HTTP_401_UNAUTHORIZED
            )
        except paramiko.SSHException as e:
            return Response(
                {'error': f'SSH连接错误: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        except Exception as e:
            return Response(
                {'error': f'获取MAC地址失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=True, methods=['post'])
    def upload_file(self, request, pk=None):
        """上传文件到主机"""
        import paramiko
        import os
        from django.core.files.storage import default_storage
        
        host = self.get_object()
        uploaded_file = request.FILES.get('file')
        target_dir = request.data.get('target_dir', '/tmp')  # 获取目标目录，默认/tmp
        
        if not uploaded_file:
            return Response(
                {'error': '没有选择文件'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # 保存文件到临时位置
        temp_file_path = default_storage.save(f'tmp/{uploaded_file.name}', uploaded_file)
        temp_file_full_path = default_storage.path(temp_file_path)
        
        ssh = None
        sftp = None
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接SSH
            if host.auth_type == 'password':
                ssh.connect(
                    host.ip,
                    port=host.port,
                    username=host.username,
                    password=host.password,
                    timeout=10,
                    banner_timeout=10
                )
            else:  # key
                from io import StringIO
                key_file = StringIO(host.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(
                    host.ip,
                    port=host.port,
                    username=host.username,
                    pkey=pkey,
                    timeout=10,
                    banner_timeout=10
                )
            
            # 使用SFTP上传文件
            sftp = ssh.open_sftp()
            
            # 确保目标目录路径正确
            if not target_dir or target_dir.strip() == '':
                target_dir = '/tmp'
            
            # 构建远程文件路径
            remote_path = os.path.join(target_dir, uploaded_file.name).replace('\\', '/')
            
            # 上传文件
            sftp.put(temp_file_full_path, remote_path)
            
            # 设置文件权限
            try:
                sftp.chmod(remote_path, 0o644)
            except:
                pass  # 权限设置失败不影响上传
            
            return Response({
                'message': '文件上传成功',
                'filename': uploaded_file.name,
                'path': remote_path,
                'size': uploaded_file.size
            })
            
        except paramiko.AuthenticationException:
            return Response(
                {'error': 'SSH认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )
        except paramiko.SSHException as e:
            return Response(
                {'error': f'SSH连接错误: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        except Exception as e:
            return Response(
                {'error': f'文件上传失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        finally:
            # 确保资源被正确释放
            try:
                if sftp:
                    sftp.close()
            except:
                pass
            
            try:
                if ssh:
                    ssh.close()
            except:
                pass
            
            # 删除本地临时文件
            try:
                if default_storage.exists(temp_file_path):
                    default_storage.delete(temp_file_path)
            except:
                pass
    
    @action(detail=True, methods=['post'])
    def download_file(self, request, pk=None):
        """从主机下载文件"""
        import paramiko
        import os
        import tempfile
        from django.http import FileResponse
        from django.core.files.storage import default_storage
        
        host = self.get_object()
        remote_path = request.data.get('remote_path')
        
        if not remote_path:
            return Response(
                {'error': '请提供远程文件路径'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        ssh = None
        sftp = None
        temp_file = None
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接SSH
            if host.auth_type == 'password':
                ssh.connect(
                    host.ip,
                    port=host.port,
                    username=host.username,
                    password=host.password,
                    timeout=10,
                    banner_timeout=10
                )
            else:  # key
                from io import StringIO
                key_file = StringIO(host.ssh_key)
                try:
                    pkey = paramiko.RSAKey.from_private_key(key_file)
                except:
                    key_file = StringIO(host.ssh_key)
                    pkey = paramiko.DSSKey.from_private_key(key_file)
                ssh.connect(
                    host.ip,
                    port=host.port,
                    username=host.username,
                    pkey=pkey,
                    timeout=10,
                    banner_timeout=10
                )
            
            # 使用SFTP下载文件
            sftp = ssh.open_sftp()
            
            # 检查远程文件是否存在
            try:
                sftp.stat(remote_path)
            except FileNotFoundError:
                return Response(
                    {'error': f'远程文件不存在: {remote_path}'},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # 获取远程文件的基本名称
            filename = os.path.basename(remote_path)
            
            # 创建临时文件
            temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f'_{filename}')
            temp_file_path = temp_file.name
            temp_file.close()
            
            # 下载文件
            sftp.get(remote_path, temp_file_path)
            
            # 获取文件大小
            file_size = os.path.getsize(temp_file_path)
            
            # 返回文件流
            response = FileResponse(
                open(temp_file_path, 'rb'),
                as_attachment=True,
                filename=filename
            )
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Length'] = file_size
            
            # 记录审计日志
            from .models import AuditLog
            from django.utils import timezone
            AuditLog.objects.create(
                level='info',
                action='file_download',
                host=host,
                host_ip=host.ip,
                host_name=host.name,
                title=f'📥 文件下载',
                message=f'用户从主机 {host.name} ({host.ip}) 下载文件: {remote_path}',
                user=request.user,
                extra_data={
                    'download_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'remote_path': remote_path,
                    'filename': filename,
                    'file_size': file_size
                }
            )
            
            return response
            
        except paramiko.AuthenticationException:
            return Response(
                {'error': 'SSH认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )
        except paramiko.SSHException as e:
            return Response(
                {'error': f'SSH连接错误: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        except FileNotFoundError:
            return Response(
                {'error': f'文件不存在: {remote_path}'},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            return Response(
                {'error': f'文件下载失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        finally:
            # 确保资源被正确释放
            try:
                if sftp:
                    sftp.close()
            except:
                pass
            
            try:
                if ssh:
                    ssh.close()
            except:
                pass
    
    @action(detail=True, methods=['post'])
    def collect_system_info(self, request, pk=None):
        """采集主机系统信息"""
        import paramiko
        import re
        from django.utils import timezone
        
        host = self.get_object()
        
        try:
            # 建立SSH连接
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 认证连接
            if host.auth_type == 'password':
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           password=host.password, timeout=15)
            else:
                from io import StringIO
                key_file = StringIO(host.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           pkey=pkey, timeout=15)
            
            collected_info = {}
            
            # 1. 采集操作系统信息
            stdin, stdout, stderr = ssh.exec_command('cat /etc/os-release 2>/dev/null || lsb_release -a 2>/dev/null')
            os_info = stdout.read().decode('utf-8')
            
            # 解析系统类型和版本
            if 'Ubuntu' in os_info:
                host.os_type = 'Ubuntu'
                version_match = re.search(r'VERSION="([^"]+)"', os_info)
                if version_match:
                    host.os_version = version_match.group(1)
            elif 'CentOS' in os_info:
                host.os_type = 'CentOS'
                version_match = re.search(r'VERSION="([^"]+)"', os_info)
                if version_match:
                    host.os_version = version_match.group(1)
            elif 'Red Hat' in os_info or 'RHEL' in os_info:
                host.os_type = 'RedHat'
                version_match = re.search(r'VERSION="([^"]+)"', os_info)
                if version_match:
                    host.os_version = version_match.group(1)
            elif 'Debian' in os_info:
                host.os_type = 'Debian'
                version_match = re.search(r'VERSION="([^"]+)"', os_info)
                if version_match:
                    host.os_version = version_match.group(1)
            
            collected_info['os_type'] = host.os_type
            collected_info['os_version'] = host.os_version
            
            # 2. 采集内核版本
            stdin, stdout, stderr = ssh.exec_command('uname -r')
            host.os_kernel = stdout.read().decode('utf-8').strip()
            collected_info['os_kernel'] = host.os_kernel
            
            # 3. 采集CPU信息
            # CPU核心数
            stdin, stdout, stderr = ssh.exec_command('nproc')
            try:
                host.cpu_cores = int(stdout.read().decode('utf-8').strip())
                collected_info['cpu_cores'] = host.cpu_cores
            except:
                pass
            
            # CPU架构
            stdin, stdout, stderr = ssh.exec_command('uname -m')
            host.cpu_arch = stdout.read().decode('utf-8').strip()
            collected_info['cpu_arch'] = host.cpu_arch
            
            # CPU型号
            stdin, stdout, stderr = ssh.exec_command("cat /proc/cpuinfo | grep 'model name' | head -1 | cut -d':' -f2 | sed 's/^[ \\t]*//'")
            host.cpu_model = stdout.read().decode('utf-8').strip()
            collected_info['cpu_model'] = host.cpu_model
            
            # 4. 采集内存信息
            stdin, stdout, stderr = ssh.exec_command("free -m | grep Mem | awk '{print $2,$3}'")
            try:
                output = stdout.read().decode('utf-8').strip().split()
                memory_total_mb = int(output[0])
                memory_used_mb = int(output[1])
                host.memory_total = memory_total_mb
                host.memory_used = memory_used_mb
                memory_gb = round(memory_total_mb / 1024, 1)
                host.memory_info = f"{memory_gb}GB"
                collected_info['memory_total'] = memory_total_mb
                collected_info['memory_used'] = memory_used_mb
                collected_info['memory_info'] = host.memory_info
            except:
                pass
            
            # 5. 采集磁盘信息
            stdin, stdout, stderr = ssh.exec_command("df -h / | tail -1 | awk '{print $2}'")
            disk_size = stdout.read().decode('utf-8').strip()
            host.disk_info = disk_size
            collected_info['disk_info'] = disk_size
            
            # 转换为GB并采集已使用量
            try:
                stdin, stdout, stderr = ssh.exec_command("df -BG / | tail -1 | awk '{print $2,$3}' | sed 's/G//g'")
                output = stdout.read().decode('utf-8').strip().split()
                disk_total_gb = int(output[0])
                disk_used_gb = int(output[1])
                host.disk_total = disk_total_gb
                host.disk_used = disk_used_gb
                collected_info['disk_total'] = disk_total_gb
                collected_info['disk_used'] = disk_used_gb
            except:
                pass
            
            # 6. 采集网络信息
            # 公网IP (ens33)
            stdin, stdout, stderr = ssh.exec_command("ip addr show ens33 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1")
            ens33_ip = stdout.read().decode('utf-8').strip()
            if ens33_ip:
                host.public_ip = ens33_ip
                collected_info['public_ip'] = ens33_ip
            
            # 内网IP (ens37)
            stdin, stdout, stderr = ssh.exec_command("ip addr show ens37 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1")
            ens37_ip = stdout.read().decode('utf-8').strip()
            if ens37_ip:
                host.private_ip = ens37_ip
                collected_info['private_ip'] = ens37_ip
            
            # 记录采集时间
            host.info_collected_at = timezone.now()
            collected_info['info_collected_at'] = host.info_collected_at.isoformat()
            
            # 保存主机信息
            host.save()
            
            ssh.close()
            
            # 创建审计日志
            AuditLog.objects.create(
                level='info',
                action='user_action',
                host=host,
                host_ip=host.ip,
                host_name=host.name,
                title='采集主机系统信息',
                message=f'成功采集主机 {host.name} ({host.ip}) 的系统信息',
                user=request.user,
                extra_data={
                    'collected_info': collected_info,
                    'action_type': 'collect_system_info'
                }
            )
            
            return Response({
                'message': '系统信息采集成功',
                'data': collected_info
            })
            
        except paramiko.AuthenticationException:
            return Response(
                {'error': 'SSH认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )
        except Exception as e:
            return Response(
                {'error': f'系统信息采集失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        finally:
            try:
                if ssh:
                    ssh.close()
            except:
                pass


class UserViewSet(viewsets.ModelViewSet):
    """用户管理视图集"""
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['username', 'email', 'first_name', 'last_name']
    ordering_fields = ['username', 'date_joined']
    permission_classes = [IsAuthenticated]  # 移除HasPermission，使用自定义权限检查
    
    def get_queryset(self):
        """
        普通用户只能看到自己的信息
        超级管理员可以看到所有用户
        """
        queryset = super().get_queryset()
        user = self.request.user
        
        if not user.is_superuser:
            # 普通用户只能看到自己
            queryset = queryset.filter(id=user.id)
        
        return queryset
    
    def get_serializer_class(self):
        """根据操作类型选择序列化器"""
        if self.action in ['update', 'partial_update']:
            return UserDetailSerializer
        return UserSerializer
    
    def create(self, request, *args, **kwargs):
        """创建用户 - 仅管理员"""
        if not request.user.is_superuser:
            return Response(
                {'error': '只有超级管理员可以创建用户'},
                status=status.HTTP_403_FORBIDDEN
            )
        return super().create(request, *args, **kwargs)
    
    def update(self, request, *args, **kwargs):
        """更新用户 - 普通用户只能更新自己"""
        user_id = kwargs.get('pk')
        if not request.user.is_superuser and str(request.user.id) != str(user_id):
            return Response(
                {'error': '您只能修改自己的信息'},
                status=status.HTTP_403_FORBIDDEN
            )
        return super().update(request, *args, **kwargs)
    
    def partial_update(self, request, *args, **kwargs):
        """部分更新用户 - 普通用户只能更新自己"""
        user_id = kwargs.get('pk')
        if not request.user.is_superuser and str(request.user.id) != str(user_id):
            return Response(
                {'error': '您只能修改自己的信息'},
                status=status.HTTP_403_FORBIDDEN
            )
        return super().partial_update(request, *args, **kwargs)
    
    def destroy(self, request, *args, **kwargs):
        """删除用户 - 仅管理员"""
        if not request.user.is_superuser:
            return Response(
                {'error': '只有超级管理员可以删除用户'},
                status=status.HTTP_403_FORBIDDEN
            )
        return super().destroy(request, *args, **kwargs)
    
    def perform_update(self, serializer):
        """
        更新用户信息时的权限检查
        普通用户不能修改敏感字段
        """
        # 如果不是超级管理员，移除敏感字段
        if not self.request.user.is_superuser:
            # 移除这些字段，防止非超级管理员修改
            self.request.data.pop('is_superuser', None)
            self.request.data.pop('is_staff', None)
            self.request.data.pop('is_active', None)
            self.request.data.pop('can_use_ssh', None)
            self.request.data.pop('groups', None)
            self.request.data.pop('user_permissions', None)
        
        serializer.save()
    
    @action(detail=False, methods=['get'])
    def me(self, request):
        """获取当前登录用户信息"""
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)
    
    @action(detail=True, methods=['post'])
    def change_password(self, request, pk=None):
        """管理员修改用户密码"""
        if not request.user.is_superuser:
            return Response(
                {'error': '只有管理员可以修改用户密码'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        user = self.get_object()
        password = request.data.get('password')
        
        if not password:
            return Response(
                {'error': '请提供新密码'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        if len(password) < 6:
            return Response(
                {'error': '密码长度不能少于6位'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        user.set_password(password)
        user.save()
        
        return Response({'message': '密码修改成功'})


class GroupViewSet(viewsets.ModelViewSet):
    """用户组管理视图集 - 仅超级管理员可访问"""
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name']
    ordering_fields = ['name']
    permission_classes = [IsAuthenticated, IsAdminUser]  # 仅管理员可访问


class RoleViewSet(viewsets.ModelViewSet):
    """角色管理视图集 - 仅超级管理员可访问"""
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'created_at']
    permission_classes = [IsAuthenticated, IsAdminUser]  # 仅管理员可访问
    
    def create(self, request, *args, **kwargs):
        """创建角色"""
        print(f"[RoleViewSet] 创建角色 - 接收的数据: {request.data}")
        response = super().create(request, *args, **kwargs)
        print(f"[RoleViewSet] 创建角色 - 返回的数据: {response.data}")
        return response
    
    def update(self, request, *args, **kwargs):
        """更新角色"""
        print(f"[RoleViewSet] 更新角色 - 接收的数据: {request.data}")
        response = super().update(request, *args, **kwargs)
        print(f"[RoleViewSet] 更新角色 - 返回的数据: {response.data}")
        return response
    
    @action(detail=True, methods=['post'])
    def permissions(self, request, pk=None):
        """更新角色权限"""
        role = self.get_object()
        permissions = request.data.get('permissions', [])
        
        role.permissions = permissions
        role.save()
        
        serializer = self.get_serializer(role)
        return Response(serializer.data)


@api_view(['POST'])
@permission_classes([AllowAny])
def register(request):
    """用户注册"""
    serializer = RegisterSerializer(data=request.data)
    if serializer.is_valid():
        user = serializer.save()
        token, created = Token.objects.get_or_create(user=user)
        return Response({
            'token': token.key,
            'user': {
                'id': user.id,
                'username': user.username,
                'email': user.email,
                'is_superuser': user.is_superuser,
                'can_use_ssh': False  # 新注册用户默认不能使用SSH
            }
        }, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([AllowAny])
def login(request):
    """用户登录"""
    serializer = LoginSerializer(data=request.data)
    if serializer.is_valid():
        username = serializer.validated_data['username']
        password = serializer.validated_data['password']
        
        user = authenticate(username=username, password=password)
        if user:
            token, created = Token.objects.get_or_create(user=user)
            
            # 获取用户扩展信息
            try:
                profile = user.profile
                can_use_ssh = profile.can_use_ssh
            except UserProfile.DoesNotExist:
                # 如果没有profile，创建一个
                profile = UserProfile.objects.create(user=user, can_use_ssh=False)
                can_use_ssh = False
            
            return Response({
                'token': token.key,
                'user': {
                    'id': user.id,
                    'username': user.username,
                    'email': user.email,
                    'first_name': user.first_name,
                    'last_name': user.last_name,
                    'is_superuser': user.is_superuser,
                    'is_staff': user.is_staff,
                    'can_use_ssh': can_use_ssh
                }
            })
        else:
            return Response(
                {'error': '用户名或密码错误'},
                status=status.HTTP_401_UNAUTHORIZED
            )
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
def logout(request):
    """用户登出"""
    try:
        # 删除用户token
        request.user.auth_token.delete()
        return Response({'message': '成功登出'}, status=status.HTTP_200_OK)
    except Exception as e:
        return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


@api_view(['GET', 'PATCH'])
def current_user(request):
    """获取或更新当前登录用户信息"""
    user = request.user
    
    if request.method == 'GET':
        try:
            profile = user.profile
            can_use_ssh = profile.can_use_ssh
            avatar = profile.avatar
        except UserProfile.DoesNotExist:
            profile = UserProfile.objects.create(user=user, can_use_ssh=False)
            can_use_ssh = False
            avatar = ''
        
        return Response({
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'is_superuser': user.is_superuser,
            'is_staff': user.is_staff,
            'can_use_ssh': can_use_ssh,
            'avatar': avatar
        })
    
    elif request.method == 'PATCH':
        # 如果要修改密码
        if 'new_password' in request.data and 'old_password' in request.data:
            # 验证旧密码
            if not user.check_password(request.data['old_password']):
                return Response(
                    {'error': '旧密码不正确'},
                    status=status.HTTP_400_BAD_REQUEST
                )
            # 设置新密码
            user.set_password(request.data['new_password'])
        
        # 更新用户信息
        if 'email' in request.data:
            user.email = request.data['email']
        if 'first_name' in request.data:
            user.first_name = request.data['first_name']
        user.save()
        
        # 更新或创建UserProfile
        profile, created = UserProfile.objects.get_or_create(user=user)
        if 'avatar' in request.data:
            profile.avatar = request.data['avatar']
            profile.save()
        
        return Response({
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'is_superuser': user.is_superuser,
            'is_staff': user.is_staff,
            'can_use_ssh': profile.can_use_ssh,
            'avatar': profile.avatar
        })


@api_view(['GET'])
def current_user_permissions(request):
    """获取当前用户的所有权限"""
    user = request.user
    
    # 获取用户权限
    permissions = RolePermissionService.get_user_permissions(user)
    
    # 获取用户所属的角色信息
    user_groups = user.groups.all()
    roles = Role.objects.filter(user_groups__in=user_groups).distinct()
    
    role_list = []
    for role in roles:
        role_list.append({
            'id': role.id,
            'name': role.name,
            'role_type': role.role_type,
            'permissions': role.permissions
        })
    
    return Response({
        'is_superuser': user.is_superuser,
        'permissions': list(permissions),
        'roles': role_list
    })


@api_view(['GET'])
def system_info(request):
    """获取系统信息API"""
    try:
        # CPU信息
        cpu_percent = psutil.cpu_percent(interval=1)
        cpu_count = psutil.cpu_count()
        
        # 内存信息
        memory = psutil.virtual_memory()
        memory_total = memory.total
        memory_used = memory.used
        memory_free = memory.available
        memory_percent = memory.percent
        
        # 磁盘信息
        disk = psutil.disk_usage('/')
        disk_total = disk.total
        disk_used = disk.used
        disk_free = disk.free
        disk_percent = disk.percent
        
        # 系统信息
        system_info_data = {
            'cpu': {
                'percent': round(cpu_percent, 2),
                'count': cpu_count,
            },
            'memory': {
                'total': memory_total,
                'used': memory_used,
                'free': memory_free,
                'percent': round(memory_percent, 2),
                'total_gb': round(memory_total / (1024**3), 2),
                'used_gb': round(memory_used / (1024**3), 2),
                'free_gb': round(memory_free / (1024**3), 2),
            },
            'disk': {
                'total': disk_total,
                'used': disk_used,
                'free': disk_free,
                'percent': round(disk_percent, 2),
                'total_gb': round(disk_total / (1024**3), 2),
                'used_gb': round(disk_used / (1024**3), 2),
                'free_gb': round(disk_free / (1024**3), 2),
            },
            'system': {
                'platform': platform.system(),
                'platform_release': platform.release(),
                'platform_version': platform.version(),
                'architecture': platform.machine(),
                'hostname': platform.node(),
                'processor': platform.processor(),
            }
        }
        
        return Response(system_info_data)
    except Exception as e:
        return Response({'error': str(e)}, status=500)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def host_inspection(request):
    """
    主机巡检功能 - 批量获取主机的系统资源信息
    支持筛选特定主机或巡检所有主机
    当资源使用率超过90%时会自动创建警告日志
    """
    try:
        import paramiko
        import time
        from io import StringIO
        from .models import AuditLog
        
        # 获取要巡检的主机ID列表
        host_ids = request.data.get('host_ids', [])
        
        # 获取警告阈值，默认90%
        warning_threshold = request.data.get('warning_threshold', 90.0)
        
        # 如果没有指定主机，则巡检所有主机
        if not host_ids:
            hosts = Host.objects.all()
        else:
            hosts = Host.objects.filter(id__in=host_ids)
        
        inspection_results = []
        warning_count = 0
        
        for host in hosts:
            result = {
                'id': host.id,
                'name': host.name,
                'ip': host.ip,
                'status': 'unknown',
                'cpu': None,
                'memory': None,
                'disk': None,
                'error': None
            }
            
            try:
                # 创建SSH客户端
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                
                # 连接主机
                connect_kwargs = {
                    'hostname': host.ip,
                    'port': host.port,
                    'username': host.username,
                    'timeout': 10
                }
                
                if host.auth_type == 'password' and host.password:
                    connect_kwargs['password'] = host.password
                elif host.auth_type == 'key' and host.ssh_key:
                    key_file = StringIO(host.ssh_key)
                    pkey = paramiko.RSAKey.from_private_key(key_file)
                    connect_kwargs['pkey'] = pkey
                
                ssh.connect(**connect_kwargs)
                
                # 获取CPU使用率
                stdin, stdout, stderr = ssh.exec_command(
                    "top -bn1 | grep 'Cpu(s)' | sed 's/.*, *\\([0-9.]*\\)%* id.*/\\1/' | awk '{print 100 - $1}'"
                )
                cpu_usage = stdout.read().decode().strip()
                
                # 获取CPU核心数（逻辑核心）
                stdin, stdout, stderr = ssh.exec_command("nproc")
                core_count = stdout.read().decode().strip()
                
                # 获取物理核心数
                stdin, stdout, stderr = ssh.exec_command(
                    "lscpu | grep 'Core(s) per socket' | awk '{print $4}'"
                )
                physical_cores = stdout.read().decode().strip()
                
                # 获取CPU频率信息
                stdin, stdout, stderr = ssh.exec_command(
                    "lscpu | grep 'CPU MHz' | awk '{print $3}'"
                )
                cpu_freq = stdout.read().decode().strip()
                
                result['cpu'] = {
                    'usage_percent': float(cpu_usage) if cpu_usage else 0,
                    'core_count': int(core_count) if core_count else 0,
                    'physical_cores': int(physical_cores) if physical_cores else 0,
                    'current_freq': float(cpu_freq) if cpu_freq else 0,
                    'max_freq': float(cpu_freq) if cpu_freq else 0
                }
                
                # 获取内存信息
                stdin, stdout, stderr = ssh.exec_command(
                    "free -m | awk 'NR==2{printf \"%.2f %.2f %.2f %.2f\\n\", $3*100/$2, $2/1024, $3/1024, $7/1024}'"
                )
                memory_info = stdout.read().decode().strip().split()
                if len(memory_info) >= 3:
                    total_gb = float(memory_info[1])
                    used_gb = float(memory_info[2])
                    available_gb = float(memory_info[3]) if len(memory_info) > 3 else (total_gb - used_gb)
                    result['memory'] = {
                        'usage_percent': float(memory_info[0]),
                        'total_gb': total_gb,
                        'used_gb': used_gb,
                        'available_gb': available_gb,
                        'free_gb': total_gb - used_gb
                    }
                
                # 获取磁盘信息
                stdin, stdout, stderr = ssh.exec_command(
                    "df -h / | awk 'NR==2{printf \"%.2f %.2f %.2f %.2f %s\\n\", substr($5,1,length($5)-1), $2, $3, $4, $6}' | sed 's/G//g'"
                )
                disk_info = stdout.read().decode().strip().split()
                if len(disk_info) >= 3:
                    total_gb = float(disk_info[1])
                    used_gb = float(disk_info[2])
                    free_gb = float(disk_info[3]) if len(disk_info) > 3 else (total_gb - used_gb)
                    mount_point = disk_info[4] if len(disk_info) > 4 else '/'
                    result['disk'] = {
                        'usage_percent': float(disk_info[0]),
                        'total_gb': total_gb,
                        'used_gb': used_gb,
                        'free_gb': free_gb,
                        'mount_point': mount_point
                    }
                
                result['status'] = 'online'
                ssh.close()
                
                # 保存巡检历史数据
                has_warning = False
                if result['cpu'] and result['memory'] and result['disk']:
                    # 检查是否有超过90%的资源
                    if (result['cpu']['usage_percent'] >= warning_threshold or 
                        result['memory']['usage_percent'] >= warning_threshold or 
                        result['disk']['usage_percent'] >= warning_threshold):
                        has_warning = True
                    
                    InspectionHistory.objects.create(
                        host=host,
                        cpu_usage=result['cpu']['usage_percent'],
                        cpu_core_count=result['cpu'].get('core_count'),
                        cpu_frequency=result['cpu'].get('current_freq'),
                        memory_usage=result['memory']['usage_percent'],
                        memory_total=result['memory']['total_gb'],
                        memory_used=result['memory']['used_gb'],
                        memory_available=result['memory']['available_gb'],
                        disk_usage=result['disk']['usage_percent'],
                        disk_total=result['disk']['total_gb'],
                        disk_used=result['disk']['used_gb'],
                        disk_free=result['disk']['free_gb'],
                        disk_mount_point=result['disk'].get('mount_point', '/'),
                        status='online',
                        has_warning=has_warning
                    )
                    
                    # 自动解决已恢复正常的资源警告
                    auto_resolved_count = 0
                    
                    # 检查CPU是否已恢复正常（低于阈值）
                    if result['cpu']['usage_percent'] < warning_threshold:
                        resolved = AuditLog.objects.filter(
                            host=host,
                            resource_type='cpu',
                            action='threshold_exceeded',
                            is_resolved=False
                        ).update(
                            is_resolved=True,
                            resolved_at=timezone.now(),
                            resolved_by=None  # 系统自动解决
                        )
                        auto_resolved_count += resolved
                    
                    # 检查内存是否已恢复正常
                    if result['memory']['usage_percent'] < warning_threshold:
                        resolved = AuditLog.objects.filter(
                            host=host,
                            resource_type='memory',
                            action='threshold_exceeded',
                            is_resolved=False
                        ).update(
                            is_resolved=True,
                            resolved_at=timezone.now(),
                            resolved_by=None
                        )
                        auto_resolved_count += resolved
                    
                    # 检查磁盘是否已恢复正常
                    if result['disk']['usage_percent'] < warning_threshold:
                        resolved = AuditLog.objects.filter(
                            host=host,
                            resource_type='disk',
                            action='threshold_exceeded',
                            is_resolved=False
                        ).update(
                            is_resolved=True,
                            resolved_at=timezone.now(),
                            resolved_by=None
                        )
                        auto_resolved_count += resolved
                    
                    # 如果有自动解决的日志，添加到结果中
                    if auto_resolved_count > 0:
                        result['auto_resolved'] = auto_resolved_count
                
                # 检查资源使用率是否超过阈值，超过则创建警告日志
                warnings = []
                
                # 检查CPU使用率
                if result['cpu'] and result['cpu']['usage_percent'] >= warning_threshold:
                    cpu_percent = result['cpu']['usage_percent']
                    AuditLog.objects.create(
                        level='warning',
                        action='threshold_exceeded',
                        host=host,
                        host_ip=host.ip,
                        host_name=host.name,
                        resource_type='cpu',
                        resource_value=cpu_percent,
                        threshold=warning_threshold,
                        title=f'⚠️ CPU使用率超过阈值',
                        message=f'主机 {host.name} ({host.ip}) 的CPU使用率为 {cpu_percent:.2f}%，超过警告阈值 {warning_threshold}%，请及时处理以防止系统宕机。',
                        user=request.user,
                        extra_data={
                            'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                            'cpu_info': result['cpu']
                        }
                    )
                    warnings.append(f'CPU: {cpu_percent:.2f}%')
                    warning_count += 1
                
                # 检查内存使用率
                if result['memory'] and result['memory']['usage_percent'] >= warning_threshold:
                    memory_percent = result['memory']['usage_percent']
                    AuditLog.objects.create(
                        level='warning',
                        action='threshold_exceeded',
                        host=host,
                        host_ip=host.ip,
                        host_name=host.name,
                        resource_type='memory',
                        resource_value=memory_percent,
                        threshold=warning_threshold,
                        title=f'⚠️ 内存使用率超过阈值',
                        message=f'主机 {host.name} ({host.ip}) 的内存使用率为 {memory_percent:.2f}%，超过警告阈值 {warning_threshold}%，请及时处理以防止系统宕机。已使用 {result["memory"]["used_gb"]:.2f}GB / 总计 {result["memory"]["total_gb"]:.2f}GB。',
                        user=request.user,
                        extra_data={
                            'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                            'memory_info': result['memory']
                        }
                    )
                    warnings.append(f'内存: {memory_percent:.2f}%')
                    warning_count += 1
                
                # 检查磁盘使用率
                if result['disk'] and result['disk']['usage_percent'] >= warning_threshold:
                    disk_percent = result['disk']['usage_percent']
                    AuditLog.objects.create(
                        level='critical' if disk_percent >= 95 else 'warning',
                        action='threshold_exceeded',
                        host=host,
                        host_ip=host.ip,
                        host_name=host.name,
                        resource_type='disk',
                        resource_value=disk_percent,
                        threshold=warning_threshold,
                        title=f'{"🚨 磁盘空间严重不足" if disk_percent >= 95 else "⚠️ 磁盘使用率超过阈值"}',
                        message=f'主机 {host.name} ({host.ip}) 的磁盘使用率为 {disk_percent:.2f}%，{"已达到严重告警级别" if disk_percent >= 95 else "超过警告阈值 " + str(warning_threshold) + "%"}，请立即清理磁盘空间以防止系统宕机。已使用 {result["disk"]["used_gb"]:.2f}GB / 总计 {result["disk"]["total_gb"]:.2f}GB，挂载点: {result["disk"]["mount_point"]}。',
                        user=request.user,
                        extra_data={
                            'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                            'disk_info': result['disk']
                        }
                    )
                    warnings.append(f'磁盘: {disk_percent:.2f}%')
                    warning_count += 1
                
                # 将警告信息添加到结果中
                if warnings:
                    result['warnings'] = warnings
                
            except paramiko.AuthenticationException:
                result['status'] = 'auth_failed'
                result['error'] = '认证失败'
                
                # SSH认证失败记录日志
                AuditLog.objects.create(
                    level='error',
                    action='ssh_auth_failed',
                    host=host,
                    host_ip=host.ip,
                    host_name=host.name,
                    title=f'🔒 SSH认证失败',
                    message=f'主机 {host.name} ({host.ip}) SSH认证失败，请检查用户名和密码/密钥是否正确。',
                    user=request.user,
                    extra_data={
                        'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                        'error': '认证失败'
                    }
                )
            except paramiko.SSHException as e:
                result['status'] = 'ssh_error'
                result['error'] = f'SSH错误: {str(e)}'
                
                # SSH连接错误记录日志
                AuditLog.objects.create(
                    level='error',
                    action='ssh_connection_error',
                    host=host,
                    host_ip=host.ip,
                    host_name=host.name,
                    title=f'⚠️ SSH连接错误',
                    message=f'主机 {host.name} ({host.ip}) SSH连接出错: {str(e)}',
                    user=request.user,
                    extra_data={
                        'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                        'error': str(e)
                    }
                )
            except Exception as e:
                result['status'] = 'offline'
                result['error'] = str(e)
                
                # 主机离线也记录日志
                AuditLog.objects.create(
                    level='error',
                    action='host_offline',
                    host=host,
                    host_ip=host.ip,
                    host_name=host.name,
                    title=f'❌ 主机离线',
                    message=f'主机 {host.name} ({host.ip}) 无法连接，错误信息: {str(e)}',
                    user=request.user,
                    extra_data={
                        'inspection_time': time.strftime('%Y-%m-%d %H:%M:%S'),
                        'error': str(e)
                    }
                )
            
            inspection_results.append(result)
        
        return Response({
            'total': len(inspection_results),
            'online': len([r for r in inspection_results if r['status'] == 'online']),
            'offline': len([r for r in inspection_results if r['status'] != 'online']),
            'warning_count': warning_count,
            'results': inspection_results,
            'timestamp': time.time()
        })
        
    except Exception as e:
        return Response({'error': str(e)}, status=500)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def send_inspection_email(request):
    """
    发送巡检报告到用户邮箱
    """
    try:
        from django.core.mail import EmailMultiAlternatives
        from django.core.mail import get_connection
        from datetime import datetime
        import smtplib
        
        # 获取当前用户
        user = request.user
        
        # 获取用户的邮箱配置
        try:
            email_config = EmailConfig.objects.get(user=user, is_active=True)
        except EmailConfig.DoesNotExist:
            return Response({'error': '未配置邮箱或邮箱配置未启用，请先在邮箱配置页面进行配置'}, status=400)
        
        # 获取接收邮箱地址（使用配置的发件邮箱作为接收邮箱）
        user_email = email_config.email_address
        
        # 获取巡检数据
        inspection_data = request.data.get('inspection_data')
        if not inspection_data:
            return Response({'error': '缺少巡检数据'}, status=400)
        
        # 准备邮件内容
        subject = f'主机巡检报告 - {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}'
        
        # 构建HTML邮件内容
        html_content = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <style>
                body {{ font-family: Arial, 'Microsoft YaHei', sans-serif; line-height: 1.6; color: #333; }}
                .container {{ max-width: 800px; margin: 0 auto; padding: 20px; }}
                .header {{ background: linear-gradient(135deg, #ff6b9d, #c471ed); color: white; padding: 20px; border-radius: 10px; }}
                .summary {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin: 20px 0; }}
                .summary-card {{ background: #f5f7fa; padding: 15px; border-radius: 10px; border-left: 4px solid; }}
                .summary-card.total {{ border-color: #12cad6; }}
                .summary-card.online {{ border-color: #51cf66; }}
                .summary-card.offline {{ border-color: #ff6b6b; }}
                .host-card {{ background: white; border: 2px solid #e9ecef; border-radius: 10px; padding: 15px; margin: 15px 0; }}
                .host-card.online {{ border-color: #51cf66; }}
                .host-card.offline {{ border-color: #ff6b6b; }}
                .host-header {{ font-size: 18px; font-weight: bold; margin-bottom: 10px; }}
                .resource-item {{ margin: 10px 0; }}
                .resource-label {{ font-weight: bold; color: #666; }}
                .resource-value {{ color: #ff6b9d; font-size: 20px; font-weight: bold; }}
                .progress-bar {{ width: 100%; height: 8px; background: #e9ecef; border-radius: 10px; overflow: hidden; margin: 5px 0; }}
                .progress-fill {{ height: 100%; border-radius: 10px; }}
                .cpu-fill {{ background: linear-gradient(90deg, #51cf66, #8bc34a); }}
                .memory-fill {{ background: linear-gradient(90deg, #12cad6, #4dabf7); }}
                .disk-fill {{ background: linear-gradient(90deg, #ffa94d, #ffc107); }}
                .footer {{ text-align: center; color: #999; margin-top: 30px; padding-top: 20px; border-top: 1px solid #e9ecef; }}
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <h1>🔍 主机巡检报告</h1>
                    <p>巡检时间: {datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")}</p>
                    <p>接收人: {user.username}</p>
                </div>
                
                <div class="summary">
                    <div class="summary-card total">
                        <div style="font-size: 14px; color: #666;">总主机数</div>
                        <div style="font-size: 32px; font-weight: bold; color: #12cad6;">{inspection_data.get('total', 0)}</div>
                    </div>
                    <div class="summary-card online">
                        <div style="font-size: 14px; color: #666;">在线主机</div>
                        <div style="font-size: 32px; font-weight: bold; color: #51cf66;">{inspection_data.get('online', 0)}</div>
                    </div>
                    <div class="summary-card offline">
                        <div style="font-size: 14px; color: #666;">离线主机</div>
                        <div style="font-size: 32px; font-weight: bold; color: #ff6b6b;">{inspection_data.get('offline', 0)}</div>
                    </div>
                </div>
                
                <h2 style="margin-top: 30px;">📊 巡检详情</h2>
        """
        
        # 添加每台主机的详细信息
        for result in inspection_data.get('results', []):
            status_class = 'online' if result['status'] == 'online' else 'offline'
            status_text = '✅ 在线' if result['status'] == 'online' else '❌ 离线'
            
            html_content += f"""
                <div class="host-card {status_class}">
                    <div class="host-header">
                        {result['name']} ({result['ip']}) {status_text}
                    </div>
            """
            
            if result['status'] == 'online' and result.get('cpu'):
                cpu_percent = result['cpu'].get('usage_percent', 0)
                memory_percent = result.get('memory', {}).get('usage_percent', 0)
                memory_used = result.get('memory', {}).get('used_gb', 0)
                memory_total = result.get('memory', {}).get('total_gb', 0)
                disk_percent = result.get('disk', {}).get('usage_percent', 0)
                disk_used = result.get('disk', {}).get('used_gb', 0)
                disk_total = result.get('disk', {}).get('total_gb', 0)
                
                html_content += f"""
                    <div class="resource-item">
                        <span class="resource-label">🖥️ CPU:</span>
                        <span class="resource-value">{cpu_percent:.1f}%</span>
                        <div class="progress-bar">
                            <div class="progress-fill cpu-fill" style="width: {cpu_percent}%"></div>
                        </div>
                    </div>
                    <div class="resource-item">
                        <span class="resource-label">💾 内存:</span>
                        <span class="resource-value">{memory_percent:.1f}%</span>
                        <span style="color: #999; font-size: 14px;">({memory_used:.2f}GB / {memory_total:.2f}GB)</span>
                        <div class="progress-bar">
                            <div class="progress-fill memory-fill" style="width: {memory_percent}%"></div>
                        </div>
                    </div>
                    <div class="resource-item">
                        <span class="resource-label">💿 磁盘:</span>
                        <span class="resource-value">{disk_percent:.1f}%</span>
                        <span style="color: #999; font-size: 14px;">({disk_used:.2f}GB / {disk_total:.2f}GB)</span>
                        <div class="progress-bar">
                            <div class="progress-fill disk-fill" style="width: {disk_percent}%"></div>
                        </div>
                    </div>
                """
            else:
                error_msg = result.get('error', '无法连接')
                html_content += f"""
                    <div style="color: #ff6b6b; padding: 15px; background: #fff5f5; border-radius: 8px;">
                        ⚠️ 错误: {error_msg}
                    </div>
                """
            
            html_content += "</div>"
        
        html_content += """
                <div class="footer">
                    <p>💖 此邮件由 CMDB 主机巡检系统自动发送</p>
                    <p style="font-size: 12px;">如有问题，请联系系统管理员</p>
                </div>
            </div>
        </body>
        </html>
        """
        
        # 创建纯文本版本
        text_content = f"主机巡检报告\\n巡检时间: {datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')}\\n"
        text_content += f"总主机: {inspection_data.get('total', 0)} | 在线: {inspection_data.get('online', 0)} | 离线: {inspection_data.get('offline', 0)}\\n\\n"
        
        for result in inspection_data.get('results', []):
            text_content += f"主机: {result['name']} ({result['ip']}) - {'在线' if result['status'] == 'online' else '离线'}\\n"
        
        # 使用用户配置的SMTP设置发送邮件
        try:
            # 创建SMTP连接
            if email_config.use_ssl:
                connection = smtplib.SMTP_SSL(
                    email_config.smtp_server,
                    email_config.smtp_port,
                    timeout=30
                )
            else:
                connection = smtplib.SMTP(
                    email_config.smtp_server,
                    email_config.smtp_port,
                    timeout=30
                )
                connection.starttls()
            
            # 登录
            connection.login(email_config.email_address, email_config.authorization_code)
            
            # 构建邮件
            from email.mime.multipart import MIMEMultipart
            from email.mime.text import MIMEText
            
            msg = MIMEMultipart('alternative')
            msg['Subject'] = subject
            msg['From'] = email_config.email_address
            msg['To'] = user_email
            
            # 添加文本和HTML内容
            part1 = MIMEText(text_content, 'plain', 'utf-8')
            part2 = MIMEText(html_content, 'html', 'utf-8')
            msg.attach(part1)
            msg.attach(part2)
            
            # 发送邮件
            connection.sendmail(
                email_config.email_address,
                [user_email],
                msg.as_string()
            )
            connection.quit()
            
            return Response({
                'message': f'巡检报告已发送到 {user_email}',
                'email': user_email
            })
            
        except smtplib.SMTPAuthenticationError:
            return Response({'error': '邮箱认证失败，请检查授权码是否正确'}, status=400)
        except smtplib.SMTPException as e:
            return Response({'error': f'SMTP错误: {str(e)}'}, status=500)
        except Exception as e:
            return Response({'error': f'发送邮件失败: {str(e)}'}, status=500)
        
    except EmailConfig.DoesNotExist:
        return Response({'error': '未配置邮箱'}, status=400)
    except Exception as e:
        return Response({'error': f'发送邮件失败: {str(e)}'}, status=500)


class EmailConfigViewSet(viewsets.ModelViewSet):
    """邮箱配置管理视图集 - 仅超级管理员可访问"""
    serializer_class = EmailConfigSerializer
    permission_classes = [IsAuthenticated, IsAdminUser]  # 仅管理员可访问
    
    def get_queryset(self):
        """用户只能看到自己的邮箱配置"""
        return EmailConfig.objects.filter(user=self.request.user)
    
    def perform_create(self, serializer):
        """创建邮箱配置时自动关联当前用户"""
        serializer.save(user=self.request.user)
    
    @action(detail=False, methods=['get'])
    def my_config(self, request):
        """获取当前用户的邮箱配置"""
        try:
            config = EmailConfig.objects.get(user=request.user)
            serializer = self.get_serializer(config)
            return Response(serializer.data)
        except EmailConfig.DoesNotExist:
            return Response({'message': '未配置邮箱'}, status=404)
    
    @action(detail=False, methods=['post'])
    def test_connection(self, request):
        """测试邮箱连接"""
        try:
            from django.core.mail import send_mail
            from django.conf import settings
            import smtplib
            from email.mime.text import MIMEText
            
            # 获取配置
            email_address = request.data.get('email_address')
            smtp_server = request.data.get('smtp_server')
            smtp_port = request.data.get('smtp_port')
            authorization_code = request.data.get('authorization_code')
            use_ssl = request.data.get('use_ssl', True)
            
            if not all([email_address, smtp_server, smtp_port, authorization_code]):
                return Response({'error': '请填写完整的邮箱配置信息'}, status=400)
            
            # 测试连接
            try:
                if use_ssl:
                    server = smtplib.SMTP_SSL(smtp_server, int(smtp_port), timeout=10)
                else:
                    server = smtplib.SMTP(smtp_server, int(smtp_port), timeout=10)
                    server.starttls()
                
                server.login(email_address, authorization_code)
                
                # 发送测试邮件
                msg = MIMEText('这是一封测试邮件，邮箱配置成功！', 'plain', 'utf-8')
                msg['Subject'] = '邮箱配置测试'
                msg['From'] = email_address
                msg['To'] = email_address
                
                server.sendmail(email_address, [email_address], msg.as_string())
                server.quit()
                
                return Response({'message': '邮箱配置测试成功！测试邮件已发送到您的邮箱。'})
            except smtplib.SMTPAuthenticationError:
                return Response({'error': '认证失败，请检查邮箱地址和授权码是否正确'}, status=400)
            except smtplib.SMTPException as e:
                return Response({'error': f'SMTP错误: {str(e)}'}, status=400)
            except Exception as e:
                return Response({'error': f'连接失败: {str(e)}'}, status=400)
                
        except Exception as e:
            return Response({'error': f'测试失败: {str(e)}'}, status=500)


class AuditLogViewSet(viewsets.ModelViewSet):
    """审计日志管理视图集 - 仅超级管理员可访问"""
    serializer_class = AuditLogSerializer
    permission_classes = [IsAuthenticated, IsAdminUser]  # 仅管理员可访问
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['title', 'message', 'host_name', 'host_ip']
    ordering_fields = ['timestamp', 'level', 'action']
    ordering = ['-timestamp']
    
    def get_queryset(self):
        """获取审计日志，支持过滤"""
        queryset = AuditLog.objects.all()
        
        # 按级别过滤
        level = self.request.query_params.get('level')
        if level:
            queryset = queryset.filter(level=level)
        
        # 按操作类型过滤
        action = self.request.query_params.get('action')
        if action:
            queryset = queryset.filter(action=action)
        
        # 按资源类型过滤
        resource_type = self.request.query_params.get('resource_type')
        if resource_type:
            queryset = queryset.filter(resource_type=resource_type)
        
        # 按主机过滤
        host_id = self.request.query_params.get('host_id')
        if host_id:
            queryset = queryset.filter(host_id=host_id)
        
        # 按解决状态过滤
        is_resolved = self.request.query_params.get('is_resolved')
        if is_resolved is not None:
            queryset = queryset.filter(is_resolved=is_resolved.lower() == 'true')
        
        return queryset
    
    @action(detail=True, methods=['post'])
    def resolve(self, request, pk=None):
        """标记日志为已解决"""
        log = self.get_object()
        log.is_resolved = True
        log.resolved_by = request.user
        from django.utils import timezone
        log.resolved_at = timezone.now()
        log.save()
        
        serializer = self.get_serializer(log)
        return Response(serializer.data)
    
    @action(detail=False, methods=['post'])
    def bulk_resolve(self, request):
        """批量标记日志为已解决"""
        ids = request.data.get('ids', [])
        
        if not ids:
            return Response({'error': '请提供要解决的日志ID列表'}, status=400)
        
        from django.utils import timezone
        
        # 批量更新
        updated_count = AuditLog.objects.filter(
            id__in=ids,
            is_resolved=False  # 只更新未解决的
        ).update(
            is_resolved=True,
            resolved_by=request.user,
            resolved_at=timezone.now()
        )
        
        return Response({
            'message': f'成功标记 {updated_count} 条日志为已解决',
            'count': updated_count
        })
    
    @action(detail=False, methods=['post'])
    def bulk_delete(self, request):
        """批量删除日志"""
        ids = request.data.get('ids', [])
        
        if not ids:
            return Response({'error': '请提供要删除的日志ID列表'}, status=400)
        
        # 批量删除
        deleted_count, _ = AuditLog.objects.filter(id__in=ids).delete()
        
        return Response({
            'message': f'成功删除 {deleted_count} 条日志',
            'count': deleted_count
        })
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """获取审计日志统计信息"""
        from django.db.models import Count
        
        # 总数
        total_count = AuditLog.objects.count()
        
        # 未解决的数量
        unresolved_count = AuditLog.objects.filter(is_resolved=False).count()
        
        # 按级别统计
        level_stats = AuditLog.objects.values('level').annotate(count=Count('id'))
        
        # 按操作类型统计
        action_stats = AuditLog.objects.values('action').annotate(count=Count('id'))
        
        # 按资源类型统计
        resource_stats = AuditLog.objects.filter(resource_type__isnull=False).values('resource_type').annotate(count=Count('id'))
        
        # 最近24小时警告数
        from django.utils import timezone
        from datetime import timedelta
        last_24h = timezone.now() - timedelta(hours=24)
        recent_warnings = AuditLog.objects.filter(
            timestamp__gte=last_24h,
            level__in=['warning', 'critical']
        ).count()
        
        return Response({
            'total_count': total_count,
            'unresolved_count': unresolved_count,
            'recent_warnings': recent_warnings,
            'level_stats': list(level_stats),
            'action_stats': list(action_stats),
            'resource_stats': list(resource_stats)
        })


class InspectionHistoryViewSet(viewsets.ReadOnlyModelViewSet):
    """巡检历史视图集（只读）- 仅超级管理员可访问"""
    serializer_class = InspectionHistorySerializer
    permission_classes = [IsAuthenticated, IsAdminUser]  # 仅管理员可访问
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    ordering_fields = ['timestamp']
    ordering = ['-timestamp']
    
    def get_queryset(self):
        """获取巡检历史，支持过滤"""
        queryset = InspectionHistory.objects.all()
        
        # 按主机过滤
        host_id = self.request.query_params.get('host_id')
        if host_id:
            queryset = queryset.filter(host_id=host_id)
        
        # 按是否有警告过滤
        has_warning = self.request.query_params.get('has_warning')
        if has_warning is not None:
            queryset = queryset.filter(has_warning=has_warning.lower() == 'true')
        
        # 按时间范围过滤
        start_time = self.request.query_params.get('start_time')
        end_time = self.request.query_params.get('end_time')
        if start_time:
            queryset = queryset.filter(timestamp__gte=start_time)
        if end_time:
            queryset = queryset.filter(timestamp__lte=end_time)
        
        return queryset
    
    @action(detail=False, methods=['get'])
    def chart_data(self, request):
        """获取用于ECharts的图表数据"""
        host_id = request.query_params.get('host_id')
        hours = int(request.query_params.get('hours', 24))  # 默认24小时
        
        if not host_id:
            return Response({'error': '请指定主机ID'}, status=400)
        
        from django.utils import timezone
        from datetime import timedelta
        
        # 获取指定时间范围内的数据
        start_time = timezone.now() - timedelta(hours=hours)
        histories = InspectionHistory.objects.filter(
            host_id=host_id,
            timestamp__gte=start_time,
            status='online'
        ).order_by('timestamp')
        
        # 构建图表数据
        timestamps = []
        cpu_data = []
        memory_data = []
        disk_data = []
        
        for h in histories:
            timestamps.append(h.timestamp.strftime('%Y-%m-%d %H:%M:%S'))
            cpu_data.append(round(h.cpu_usage, 2))
            memory_data.append(round(h.memory_usage, 2))
            disk_data.append(round(h.disk_usage, 2))
        
        return Response({
            'timestamps': timestamps,
            'cpu': cpu_data,
            'memory': memory_data,
            'disk': disk_data
        })
    
    @action(detail=False, methods=['get'])
    def multi_host_chart(self, request):
        """获取多主机对比图表数据"""
        host_ids = request.query_params.get('host_ids', '')
        hours = int(request.query_params.get('hours', 24))
        
        if not host_ids:
            return Response({'error': '请指定主机ID列表'}, status=400)
        
        host_ids = [int(id) for id in host_ids.split(',')]
        
        from django.utils import timezone
        from datetime import timedelta
        
        start_time = timezone.now() - timedelta(hours=hours)
        
        result = {}
        for host_id in host_ids:
            try:
                host = Host.objects.get(id=host_id)
                histories = InspectionHistory.objects.filter(
                    host_id=host_id,
                    timestamp__gte=start_time,
                    status='online'
                ).order_by('timestamp')
                
                timestamps = []
                cpu_data = []
                memory_data = []
                disk_data = []
                
                for h in histories:
                    timestamps.append(h.timestamp.strftime('%Y-%m-%d %H:%M:%S'))
                    cpu_data.append(round(h.cpu_usage, 2))
                    memory_data.append(round(h.memory_usage, 2))
                    disk_data.append(round(h.disk_usage, 2))
                
                result[host.name] = {
                    'host_id': host_id,
                    'host_name': host.name,
                    'host_ip': host.ip,
                    'timestamps': timestamps,
                    'cpu': cpu_data,
                    'memory': memory_data,
                    'disk': disk_data
                }
            except Host.DoesNotExist:
                continue
        
        return Response(result)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def sync_hosts_status(request):
    """
    同步主机状态 - 通过SSH连接检测主机实际在线状态
    """
    try:
        import paramiko
        from io import StringIO
        
        # 获取所有主机
        hosts = Host.objects.all()
        
        sync_results = []
        updated_count = 0
        
        for host in hosts:
            result = {
                'id': host.id,
                'name': host.name,
                'ip': host.ip,
                'old_status': host.status,
                'new_status': 'offline',
                'message': ''
            }
            
            try:
                # 创建SSH客户端
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                
                # 连接主机
                connect_kwargs = {
                    'hostname': host.ip,
                    'port': host.port,
                    'username': host.username,
                    'timeout': 5  # 5秒超时
                }
                
                if host.auth_type == 'password' and host.password:
                    connect_kwargs['password'] = host.password
                elif host.auth_type == 'key' and host.ssh_key:
                    key_file = StringIO(host.ssh_key)
                    try:
                        pkey = paramiko.RSAKey.from_private_key(key_file)
                    except:
                        key_file = StringIO(host.ssh_key)
                        pkey = paramiko.DSSKey.from_private_key(key_file)
                    connect_kwargs['pkey'] = pkey
                
                # 尝试连接
                ssh.connect(**connect_kwargs)
                
                # 执行简单命令验证连接
                stdin, stdout, stderr = ssh.exec_command('echo "connection_test"')
                output = stdout.read().decode().strip()
                
                if 'connection_test' in output:
                    result['new_status'] = 'online'
                    result['message'] = '连接成功'
                else:
                    result['new_status'] = 'offline'
                    result['message'] = '连接验证失败'
                
                ssh.close()
                
            except paramiko.AuthenticationException:
                result['new_status'] = 'offline'
                result['message'] = 'SSH认证失败'
            except paramiko.SSHException as e:
                result['new_status'] = 'offline'
                result['message'] = f'SSH错误: {str(e)}'
            except TimeoutError:
                result['new_status'] = 'offline'
                result['message'] = '连接超时'
            except Exception as e:
                result['new_status'] = 'offline'
                result['message'] = f'连接失败: {str(e)}'
            
            # 更新数据库中的主机状态
            if host.status != result['new_status']:
                host.status = result['new_status']
                host.save()
                updated_count += 1
                result['updated'] = True
            else:
                result['updated'] = False
            
            sync_results.append(result)
        
        return Response({
            'message': f'同步完成，共检测 {len(hosts)} 台主机，更新了 {updated_count} 台主机状态',
            'total': len(hosts),
            'updated_count': updated_count,
            'online_count': len([r for r in sync_results if r['new_status'] == 'online']),
            'offline_count': len([r for r in sync_results if r['new_status'] == 'offline']),
            'results': sync_results
        })
        
    except Exception as e:
        return Response({'error': f'同步失败: {str(e)}'}, status=500)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def test_ssh_connection(request, host_id):
    """
    测试SSH连接 - 需要SSH权限
    """
    # 检查SSH权限
    if not request.user.is_superuser:
        if not RolePermissionService.has_permission(request.user, 'host.ssh'):
            return Response(
                {'error': '您没有SSH连接主机的权限'}, 
                status=status.HTTP_403_FORBIDDEN
            )
    
    try:
        import paramiko
        from io import StringIO
        
        # 获取主机信息
        try:
            host = Host.objects.get(id=host_id)
        except Host.DoesNotExist:
            return Response({'error': '主机不存在'}, status=404)
        
        # 检查认证信息
        if host.auth_type == 'password' and not host.password:
            return Response({'error': '主机未配置SSH密码'}, status=400)
        
        if host.auth_type == 'key' and not host.ssh_key:
            return Response({'error': '主机未配置SSH密钥'}, status=400)
        
        try:
            # 创建SSH客户端
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接到主机
            if host.auth_type == 'password':
                ssh.connect(
                    hostname=host.ip,
                    port=host.port,
                    username=host.username,
                    password=host.password,
                    timeout=5
                )
            else:
                key = paramiko.RSAKey.from_private_key(StringIO(host.ssh_key))
                ssh.connect(
                    hostname=host.ip,
                    port=host.port,
                    username=host.username,
                    pkey=key,
                    timeout=5
                )
            
            # 测试执行命令
            stdin, stdout, stderr = ssh.exec_command('echo "SSH连接成功"')
            output = stdout.read().decode('utf-8').strip()
            
            ssh.close()
            
            return Response({
                'success': True,
                'message': 'SSH连接测试成功！',
                'output': output,
                'host_info': {
                    'name': host.name,
                    'ip': host.ip,
                    'port': host.port,
                    'username': host.username
                }
            })
            
        except paramiko.AuthenticationException:
            return Response({
                'success': False,
                'error': 'SSH认证失败',
                'details': f'用户名: {host.username}, 请检查密码是否正确'
            }, status=401)
        except paramiko.SSHException as e:
            return Response({
                'success': False,
                'error': 'SSH连接失败',
                'details': str(e)
            }, status=500)
        except Exception as e:
            return Response({
                'success': False,
                'error': f'连接失败: {str(e)}',
                'details': f'无法连接到 {host.ip}:{host.port}'
            }, status=500)
            
    except Exception as e:
        return Response({'error': f'操作失败: {str(e)}'}, status=500)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def auto_get_mac_address(request, host_id):
    """
    自动获取主机MAC地址
    通过SSH连接到主机，自动获取网卡MAC地址
    """
    try:
        import paramiko
        from io import StringIO
        
        # 获取主机信息
        try:
            host = Host.objects.get(id=host_id)
        except Host.DoesNotExist:
            return Response({'error': '主机不存在'}, status=404)
        
        # 检查认证信息
        if host.auth_type == 'password' and not host.password:
            return Response({'error': '主机未配置SSH密码'}, status=400)
        
        if host.auth_type == 'key' and not host.ssh_key:
            return Response({'error': '主机未配置SSH密钥'}, status=400)
        
        try:
            # 创建SSH客户端
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接到主机
            if host.auth_type == 'password':
                ssh.connect(
                    hostname=host.ip,
                    port=host.port,
                    username=host.username,
                    password=host.password,
                    timeout=10
                )
            else:
                key = paramiko.RSAKey.from_private_key(StringIO(host.ssh_key))
                ssh.connect(
                    hostname=host.ip,
                    port=host.port,
                    username=host.username,
                    pkey=key,
                    timeout=10
                )
            
            # 获取MAC地址 - 使用多个命令兼容不同系统
            # 优先获取主网卡的MAC地址
            commands = [
                # Linux - 获取默认网关对应的网卡MAC
                "ip route | grep default | awk '{print $5}' | xargs -I {} ip link show {} | grep 'link/ether' | awk '{print $2}'",
                # 备选 - 获取第一个非lo网卡的MAC
                "ip link show | grep -A1 'state UP' | grep 'link/ether' | head -1 | awk '{print $2}'",
                # 再备选 - ifconfig方式
                "ifconfig | grep -A5 'flags=.*UP' | grep 'ether' | head -1 | awk '{print $2}'",
            ]
            
            mac_address = None
            for cmd in commands:
                stdin, stdout, stderr = ssh.exec_command(cmd)
                output = stdout.read().decode('utf-8').strip()
                if output and len(output) == 17 and ':' in output:
                    mac_address = output
                    break
            
            ssh.close()
            
            if mac_address:
                # 更新主机MAC地址
                host.mac_address = mac_address
                host.save()
                
                return Response({
                    'message': 'MAC地址获取成功',
                    'mac_address': mac_address,
                    'host_name': host.name,
                    'host_ip': host.ip
                })
            else:
                return Response({
                    'error': '无法获取MAC地址',
                    'details': '请手动填写MAC地址'
                }, status=500)
            
        except paramiko.AuthenticationException:
            return Response({'error': 'SSH认证失败，请检查用户名和密码'}, status=401)
        except paramiko.SSHException as e:
            return Response({'error': f'SSH连接失败: {str(e)}'}, status=500)
        except Exception as e:
            return Response({'error': f'获取MAC地址失败: {str(e)}'}, status=500)
            
    except Exception as e:
        return Response({'error': f'操作失败: {str(e)}'}, status=500)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def host_power_action(request, host_id):
    """
    主机电源管理 - 关机/重启
    支持操作: shutdown, reboot
    """
    try:
        import paramiko
        from io import StringIO
        
        action = request.data.get('action')
        if action not in ['shutdown', 'reboot']:
            return Response({'error': '不支持的操作，仅支持: shutdown, reboot'}, status=400)
        
        # 获取主机信息
        try:
            host = Host.objects.get(id=host_id)
        except Host.DoesNotExist:
            return Response({'error': '主机不存在'}, status=404)
        
        # 关机和重启操作需要SSH连接
        # 检查认证信息
        if host.auth_type == 'password' and not host.password:
            return Response({'error': '主机未配置SSH密码'}, status=400)
        
        if host.auth_type == 'key' and not host.ssh_key:
            return Response({'error': '主机未配置SSH密钥'}, status=400)
        
        try:
            # 创建SSH客户端
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接主机
            connect_kwargs = {
                'hostname': host.ip,
                'port': host.port,
                'username': host.username,
                'timeout': 10
            }
            
            if host.auth_type == 'password':
                connect_kwargs['password'] = host.password
            else:
                key_file = StringIO(host.ssh_key)
                try:
                    pkey = paramiko.RSAKey.from_private_key(key_file)
                except:
                    key_file = StringIO(host.ssh_key)
                    pkey = paramiko.DSSKey.from_private_key(key_file)
                connect_kwargs['pkey'] = pkey
            
            ssh.connect(**connect_kwargs)
            
            # 执行电源操作命令
            if action == 'shutdown':
                # 关机命令（1分钟后关机，给系统清理时间）
                command = 'sudo shutdown -h +1 "System shutdown initiated from CMDB"'
                action_text = '关机'
            elif action == 'reboot':
                # 重启命令（1分钟后重启）
                command = 'sudo reboot'
                action_text = '重启'
            
            # 执行命令
            stdin, stdout, stderr = ssh.exec_command(command)
            exit_status = stdout.channel.recv_exit_status()
            
            ssh.close()
            
            if exit_status == 0:
                # 更新主机状态
                if action == 'shutdown':
                    host.status = 'offline'
                    host.save()
                
                return Response({
                    'message': f'主机{action_text}命令已发送成功',
                    'host_name': host.name,
                    'host_ip': host.ip,
                    'action': action,
                    'note': f'主机将在1分钟后{action_text}'
                })
            else:
                error_output = stderr.read().decode('utf-8', errors='ignore')
                return Response({
                    'error': f'{action_text}命令执行失败',
                    'details': error_output
                }, status=500)
            
        except paramiko.AuthenticationException:
            return Response({'error': 'SSH认证失败：用户名或密码错误'}, status=401)
        except paramiko.SSHException as e:
            return Response({'error': f'SSH连接错误: {str(e)}'}, status=500)
        except TimeoutError:
            return Response({'error': '连接超时：主机可能已关机或网络不通'}, status=500)
        except Exception as e:
            return Response({'error': f'操作失败: {str(e)}'}, status=500)
            
    except Exception as e:
        return Response({'error': f'请求处理失败: {str(e)}'}, status=500)
